#include "SceneInitialiser.h"

SceneInitialiser::SceneInitialiser(DataLoader *pDataLoader, DX11Structure *pDX11Structure) {
	dataLoader = pDataLoader;
	sceneStructure = new SceneStructure();
	dx11Structure = pDX11Structure;
}

Optional<SceneStructure> SceneInitialiser::initScene() {
	// TODO
}

void SceneInitialiser::initWorld() {
	World *world = dataLoader->loadWorld((TCHAR*)TurnsDataModel::SAMPLE_MAP_FILE_PATH);
	sceneStructure->setWorld(world);
}

void SceneInitialiser::initVertices() {
	World *world = sceneStructure->getWorld();
	std::vector<ColoredVertex *> vertexData = dataLoader->loadColorVertices(world);
	int coloredVerticesCount = vertexData.size();
	if (coloredVerticesCount == 0) {
		WindowOperations::showDefaultErrorMessage(TurnsDataModel::LOADER_MAP_STRUCTURE_ERROR_MESSAGE);
		throw "InitVerticesException";
	}
	ColoredVertex * coloredVertices = new ColoredVertex[coloredVerticesCount];
	for (int i = 0; i < coloredVerticesCount; ++i) {
		coloredVertices[i] = *vertexData[i];
	}
}

void SceneInitialiser::compileShaders() {
	ID3DBlob *vertexColoredShaderBuffer;
	ID3DBlob *vertexTexturedShaderBuffer;
	ID3DBlob *pixelColoredShaderBuffer;
	ID3DBlob *pixelTexturedShaderBuffer;

	compileShader(L"VertexColoredShader.hlsl", "vertexColoredShader", &vertexColoredShaderBuffer);
	compileShader(L"VertexTexturedShader.hlsl", "vertexTexturedShader", &vertexTexturedShaderBuffer);
	compileShader(L"PixelColoredShader.hlsl", "pixelColoredShader", &pixelColoredShaderBuffer);
	compileShader(L"PixelTexturedShader.hlsl", "pixelTexturedShader", &pixelTexturedShaderBuffer);

	sceneStructure->setVertexColoredShaderBuffer(vertexColoredShaderBuffer);
	sceneStructure->setVertexTexturedShaderBuffer(vertexTexturedShaderBuffer);
	sceneStructure->setPixelColoredShaderBuffer(pixelColoredShaderBuffer);
	sceneStructure->setPixelTexturedShaderBuffer(pixelTexturedShaderBuffer);
}

void SceneInitialiser::compileShader(wstring pShaderFileName, string pShaderEntryPoint, ID3DBlob **pShaderBuffer) {
	HRESULT hResult;
	ID3DBlob *shaderErrorMessages;

	hResult = D3DCompileFromFile(
		pShaderFileName.c_str(),
		NULL,
		NULL,
		pShaderEntryPoint.c_str(),
		"vs_5_0",
		D3DCOMPILE_DEBUG,
		0,
		pShaderBuffer,
		&shaderErrorMessages
	);
	if (FAILED(hResult)) {
		char *errorMessage = (char*)shaderErrorMessages->GetBufferPointer();
		MessageBoxA(NULL, errorMessage, "Shader Compile Error", MB_OK);
		throw pShaderEntryPoint + "Exception";
	}
}

void SceneInitialiser::createVertexShaders() {
	ID3DBlob *vertexColoredShaderBuffer = sceneStructure->getVertexColoredShaderBuffer();
	ID3DBlob *vertexTexturedShaderBuffer = sceneStructure->getVertexTexturedShaderBuffer();
	ID3D11VertexShader *vertexColoredShader;
	ID3D11VertexShader *vertexTexturedShader;

	createVertexShader(vertexColoredShaderBuffer, &vertexColoredShader);
	createVertexShader(vertexTexturedShaderBuffer, &vertexTexturedShader);

	sceneStructure->setVertexColoredShader(vertexColoredShader);
	sceneStructure->setVertexTexturedShader(vertexTexturedShader);
}

void SceneInitialiser::createVertexShader(ID3DBlob *pShaderBuffer, ID3D11VertexShader **pShader) {
	ID3D11Device * device = dx11Structure->getDevice();

	HRESULT hResult = device->CreateVertexShader(
		pShaderBuffer->GetBufferPointer(),
		pShaderBuffer->GetBufferSize(),
		NULL,
		pShader
	);
	if (FAILED(hResult)) {
		WindowOperations::showDefaultErrorMessage(TurnsDataModel::DX11_CREATE_VERTEX_SHADER_ERROR_MESSAGE);
		throw TurnsDataModel::DX11_CREATE_VERTEX_SHADER_ERROR_MESSAGE;
	}
}

void SceneInitialiser::createPixelShaders() {
	ID3DBlob *pixelColoredShaderBuffer = sceneStructure->getPixelColoredShaderBuffer();
	ID3DBlob *pixelTexturedShaderBuffer = sceneStructure->getPixelTexturedShaderBuffer();
	ID3D11PixelShader *pixelColoredShader;
	ID3D11PixelShader *pixelTexturedShader;

	createPixelShader(pixelColoredShaderBuffer, &pixelColoredShader);
	createPixelShader(pixelTexturedShaderBuffer, &pixelTexturedShader);

	sceneStructure->setPixelColoredShader(pixelColoredShader);
	sceneStructure->setPixelTexturedShader(pixelTexturedShader);
}

void SceneInitialiser::createPixelShader(ID3DBlob *pShaderBuffer, ID3D11PixelShader **pShader) {
	ID3D11Device * device = dx11Structure->getDevice();

	HRESULT hResult = device->CreatePixelShader(
		pShaderBuffer->GetBufferPointer(),
		pShaderBuffer->GetBufferSize(),
		NULL,
		pShader
	);
	if (FAILED(hResult)) {
		WindowOperations::showDefaultErrorMessage(TurnsDataModel::DX11_CREATE_PIXEL_SHADER_ERROR_MESSAGE);
		throw TurnsDataModel::DX11_CREATE_PIXEL_SHADER_ERROR_MESSAGE;
	}
}

void SceneInitialiser::createVertexBuffers() {
	// TODO

}

void SceneInitialiser::createVertexBuffer(size_t pVertexByteWidth, void *pVertexData, ID3D11Buffer **pVertexBuffer) {
	D3D11_BUFFER_DESC vertexBufferDescription;
	D3D11_SUBRESOURCE_DATA vertexSubresourceData;
	ID3D11Device *device = dx11Structure->getDevice();

	ZeroMemory(&vertexBufferDescription, sizeof(vertexBufferDescription));
	vertexBufferDescription.Usage = D3D11_USAGE_DEFAULT;
	vertexBufferDescription.ByteWidth = pVertexByteWidth;
	vertexBufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexBufferDescription.CPUAccessFlags = 0;
	vertexBufferDescription.MiscFlags = 0;

	ZeroMemory(&vertexSubresourceData, sizeof(vertexSubresourceData));
	vertexSubresourceData.pSysMem = pVertexData;
	vertexSubresourceData.SysMemPitch = 0;
	vertexSubresourceData.SysMemSlicePitch = 0;

	HRESULT hResult = device->CreateBuffer(&vertexBufferDescription, &vertexSubresourceData, pVertexBuffer);
	if (FAILED(hResult)) {
		WindowOperations::showDefaultErrorMessage(TurnsDataModel::DX11_CREATE_BUFFER_ERROR_MESSAGE);
		throw TurnsDataModel::DX11_CREATE_BUFFER_ERROR_MESSAGE;
	}
}

void SceneInitialiser::createIndexBuffers() {
	// TODO
}

void SceneInitialiser::createIndexBuffer(int pIndexCount, DWORD *pIndices, ID3D11Buffer **pIndexBuffer) {
	D3D11_BUFFER_DESC indexBufferDescription;
	D3D11_SUBRESOURCE_DATA indexSubresourceData;
	ID3D11Device *device = dx11Structure->getDevice();

	indexBufferDescription.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDescription.ByteWidth = sizeof(DWORD) * pIndexCount;
	indexBufferDescription.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDescription.CPUAccessFlags = 0;
	indexBufferDescription.MiscFlags = 0;
	indexBufferDescription.StructureByteStride = 0;

	ZeroMemory(&indexSubresourceData, sizeof(indexSubresourceData));
	indexSubresourceData.pSysMem = pIndices;
	indexSubresourceData.SysMemPitch = 0;
	indexSubresourceData.SysMemSlicePitch = 0;

	HRESULT hResult = device->CreateBuffer(&indexBufferDescription, &indexSubresourceData, pIndexBuffer);
	if (FAILED(hResult)) {
		WindowOperations::showDefaultErrorMessage(TurnsDataModel::DX11_CREATE_BUFFER_ERROR_MESSAGE);
		throw TurnsDataModel::DX11_CREATE_BUFFER_ERROR_MESSAGE;
	}
}

void SceneInitialiser::createConstantBuffers() {

}

void SceneInitialiser::createInputLayouts() {

}

void SceneInitialiser::createAndSetViewport() {

}

void SceneInitialiser::initCamera() {

}

void SceneInitialiser::createWireFrame() {

}

void SceneInitialiser::createShaderResources() {

}

void SceneInitialiser::prepareData() {

}
